﻿using System;
using UnityEngine;
using UnityEngine.UIElements;
using Math = winS.Unity.Math;

namespace winS.UnityEditor.ProcessEditor
{
    /// <summary>
    /// 缩放功能
    /// </summary>
    public class Zoomer : Manipulator
    {
        public static readonly int defaultScaleStep = 40;
        public static readonly float defaultMinScale = 0.1f;
        public static readonly float defaultMaxScale = 1.9f;

        public event Action<float> onScaleChanged;

        public float ratio => (currentScale - minScale) / (maxScale - minScale);
        public float minScale { get; private set; } = defaultMinScale;
        public float maxScale { get; private set; } = defaultMaxScale;
        public float currentScale { get; private set; } = 1f;

        private float zoomInterval;

        public Zoomer(StepGraphView stepGraphView) : base(stepGraphView)
        {
            stepGraphView.RegisterCallback<WheelEvent>(WheelCallback);
            SetZoom(minScale, maxScale, currentScale, (maxScale - minScale) / defaultScaleStep);
        }

        public void SetZoom(float currentScale)
        {
            this.currentScale = currentScale;
            onScaleChanged?.Invoke((currentScale - minScale) / (maxScale - minScale));
            viewTransform.scale = new Vector3(currentScale, currentScale, 1f);
        }
        public void SetZoom(float minScale, float maxScale, float currentScale, float zoomInterval)
        {
            this.minScale = minScale;
            this.maxScale = maxScale;
            this.zoomInterval = zoomInterval;
            SetZoom(currentScale);
        }

        private void WheelCallback(WheelEvent wheelEvent)
        {
            if (stepGraphView.panel.GetCapturingElement(PointerId.mousePointerId) != null) return;

            Vector2 localScalePoint = stepGraphView.ChangeCoordinatesTo(contentViewContainer, wheelEvent.localMousePosition);

            currentScale = Math.Clamp(currentScale + zoomInterval * Math.Sign(-wheelEvent.delta.y), minScale, maxScale);
            onScaleChanged?.Invoke((currentScale - minScale) / (maxScale - minScale));
            viewTransform.scale = new Vector3(currentScale, currentScale, currentScale);

            Vector2 newLocalScalePoint = stepGraphView.ChangeCoordinatesTo(contentViewContainer, wheelEvent.localMousePosition);
            Vector2 localOffset = newLocalScalePoint - localScalePoint;
            Vector2 worldOffset = contentViewContainer.worldTransform.MultiplyVector(localOffset);
            viewTransform.position += (Vector3)worldOffset;

            wheelEvent.StopPropagation();
        }
    }
}